#include "app_config.hpp"
#include "imgui/imgui.h"
#include "imgui/imgui_stdlib.h"
#include "gui/ui_component.hpp"
#include "fmt/format.h"

#include <regex>

namespace Config
{
    using namespace ImGui;

    void GroupItem::Render()
    {
        BeginDisabled(!this->enabled);
        if (this->section_name.empty() || CollapsingHeader(this->section_name.c_str(), enabled ? ImGuiTreeNodeFlags_DefaultOpen : 0))
        {
            for (auto const& child : children)
            {
                child->Render();
            }
        }
        EndDisabled();
    }

    void GroupItem::Sync(bool read)
    {
        for (auto const& child : children)
            child->Sync(read);
    }

    void IntItem::Render()
    {
        BeginDisabled(!this->enabled);
        InputInt(description.c_str(), &value);
        if (!tooltip.empty())
            ::HelperMaker(tooltip.c_str(), true);
        EndDisabled();
    }

    void IntItem::Sync(bool read)
    {
        assert(associate_config != nullptr);
        if (read)
            try
        {
            value = std::stol(*associate_config);
        }
        catch (std::exception&)
        {
            value = 0;
        }
        else
            *associate_config = std::to_string(value);
    }

    void RealItem::Render()
    {
        BeginDisabled(!this->enabled);
        InputDouble(description.c_str(), &value, 0, 0, "%.2f");
        if (!tooltip.empty())
            ::HelperMaker(tooltip.c_str(), true);
        EndDisabled();
    }

    void RealItem::Sync(bool read)
    {
        assert(associate_config != nullptr);
        if (read)
        {
            try
            {
                value = std::stod(*associate_config);
            }
            catch (std::exception&)
            {
                value = 0.0;
            }
        }
        else
            *associate_config = std::to_string(value);
    }

    void SwitchItem::Render()
    {
        BeginDisabled(!this->enabled);
        Checkbox(description.c_str(), &value);
        if (!tooltip.empty())
            ::HelperMaker(tooltip.c_str(), true);
        EndDisabled();
    }

    void SwitchItem::Sync(bool read)
    {
        assert(associate_config != nullptr);
        if (read)
        {
            // trust empty string and none "true" string as false
            if (associate_config->empty() || value_text[0] != *associate_config)
                value = false;
            else
                value = true;
        }
        else
        {
            *associate_config = value_text[static_cast<int>(!value)];
        }
    }

    void EnumItem::Render()
    {
        BeginDisabled(!this->enabled);
        //const char* text = nullptr;
        //text = item_getter(data, selected);
        Combo(description.c_str(), &selected, item_getter, data, count);
        if (!tooltip.empty())
            ::HelperMaker(tooltip.c_str(), true);
        EndDisabled();
    }

    void EnumItem::Sync(bool read)
    {
        assert(associate_config != nullptr);
        if (read)
        {
            int index = -1;
            for (int i = 0; i < count; ++i)
            {
                const char* text = nullptr;
                text = item_getter(data, i);
                if (!text)
                    break;
                if (strcmp(text, associate_config->c_str()) == 0)
                {
                    index = i;
                    break;
                }
            }
            selected = index;
        }
        else
        {
            const char* text = nullptr;
            text = item_getter(data, selected);
            if (text)
                *associate_config = text;
        }
    }

    void TextItem::Render()
    {
        BeginDisabled(!this->enabled);
        if (multi_line)
        {
            InputTextMultiline(description.c_str(), &text);
        }
        else
        {
            InputText(description.c_str(), &text);
        }
        EndDisabled();
        if (!tooltip.empty())
            ::HelperMaker(tooltip.c_str(), true);
    }

    void TextItem::Sync(bool read)
    {
        assert(associate_config != nullptr);
        if (read)
            text = *associate_config;
        else
            *associate_config = text;
    }

    void FunctionButton::Sync(bool read)
    {
        (void)read;
    }

    void FunctionButton::Render()
    {
        if (same_line)
            SameLine();

        if (Button(description.c_str()))
            slot();

        if (!tooltip.empty() && IsItemHovered())
            SetTooltip("%s", tooltip.c_str());
    }
    
    void TimeItem::Render ()
    {
        PushID(this);
        BeginDisabled(!enabled);
        std::string text = fmt::format("{:02d}", values[0]);
        std::string display;

        // Hour
        SetNextItemWidth(GetFontSize() * 3);
        if (BeginCombo ("##Hour", text.c_str ()))
        {
            for (int i=0;i<24;++i)
            {
                display = fmt::format("{:02d}", i);
                if (Selectable (display.c_str ()))
                {
                    values[0] = i;
                }
                if (i == values[0])
                    SetItemDefaultFocus();
            }
            EndCombo();
        }
        SameLine();
        TextUnformatted("时"); SameLine();

        // Minute
        text = fmt::format("{:02d}", values[1]);
        SetNextItemWidth(GetFontSize() * 3);
        if (BeginCombo("##Minute", text.c_str()))
        {
            for (int i = 0; i < 60; ++i)
            {
                display = fmt::format("{:02d}", i);
                if (Selectable(display.c_str()))
                {
                    values[1] = i;
                }
                if (i == values[1])
                    SetItemDefaultFocus();
            }
            EndCombo();
        }
        SameLine();
        TextUnformatted("分"); SameLine();

        // Second
        text = fmt::format("{:02d}", values[2]);
        SetNextItemWidth(GetFontSize() * 3);
        if (BeginCombo("##Second", text.c_str()))
        {
            for (int i = 0; i < 60; ++i)
            {
                display = fmt::format("{:02d}", i);
                if (Selectable(display.c_str()))
                {
                    values[2] = i;
                }
                if (i == values[2])
                    SetItemDefaultFocus();
            }
            EndCombo();
        }
        SameLine();
        TextUnformatted("秒"); SameLine();

        TextUnformatted(description.c_str());
        
        EndDisabled();
        if (!tooltip.empty())
            ::HelperMaker(tooltip.c_str(), true);
        PopID();
    }

    void TimeItem::Sync (bool read)
    {
        if (read)
        {
            memset(values, 0x0, sizeof(values));
            auto copy = *associate_config;
            if (!copy.empty ())
            {
                int i = 0;
                size_t pos, s = 0;
                while ((pos = copy.find (':', s)) != std::string::npos)
                {
                    try
                    {
                        values[i++] = std::stoi(copy.substr(s, pos - s));
                        s = pos + 1;
                    }
                    catch (...) { break; }
                }
                if (s < copy.length ())
                {
                    try
                    {
                        values[i++] = std::stoi(copy.substr(s, pos - s));
                        s = pos + 1;
                    }
                    catch (...) { }
                }
            }
        }
        else
        {
            *associate_config = fmt::format("{:02d}:{:02d}:{:02d}", values[0], values[1], values[2]);
        }
    }



}
